﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Microsoft.AspNetCore.Mvc;
using shenghua.Articles.Dto;
using shenghua.Authorization;
using shenghua.Common.Articles;
using shenghua.Common.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace shenghua.Articles
{
    public class ArticleAppService: shenghuaAppServiceBase, IArticleAppService
    {
        private readonly ArticleManager _articleManager;
        private readonly IRepository<Article> _articleRepository;

        public ArticleAppService(
            ArticleManager articleManager,
            IRepository<Article> articleRepository
            )
        {
            _articleManager = articleManager;
            _articleRepository = articleRepository;
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task<ArticleDto> Get(EntityDto input)
        {
            var item = await _articleManager.Get(input.Id);
            return new ArticleDto(item);
        }

        public async Task<ArticleDto> GetEnabled(GetArticleDto input)
        {
            var item = await _articleManager.Get(input.Id, true);
            await _articleManager.ClickArticle(item);
            var result = new ArticleDto(item);
            if (input.WithAround)
            {
                var query = _articleRepository.GetAll().Where(r => r.Enabled && r.SystemType == item.SystemType);
                var prevArticle = query.Where(r => r.CreationTime < item.CreationTime).OrderByDescending(r => r.CreationTime).FirstOrDefault();
                if(prevArticle != null)
                {
                    result.PrevArticle = new ArticleDto(prevArticle);
                }
                var nextArticle = query.Where(r => r.CreationTime > item.CreationTime).OrderBy(r => r.CreationTime).FirstOrDefault();
                if (nextArticle != null)
                {
                    result.NextArticle = new ArticleDto(nextArticle);
                }
            }
            return result;
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task<ArticleDto> Create(CreateArticleDto input)
        {
            Article article = new Article();
            input.MapTo(article);
            await _articleManager.Create(article);
            return new ArticleDto(article);
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task<ArticleDto> Update(UpdateArticleDto input)
        {
            Article article = await _articleManager.Get(input.Id);
            input.MapTo(article);
            await _articleManager.Update(article);
            return new ArticleDto(article);
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        [HttpPost]
        public async Task Delete(BatchIntIdDto input)
        {
            foreach(var id in input.Ids)
            {
                await _articleManager.Delete(id);
            }
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task AuditArticle(BatchIntIdDto input)
        {
            foreach (var id in input.Ids)
            {
                await _articleManager.AuditArticle(id);
            }
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task Enabled(EntityDto input)
        {
            await _articleManager.Enabled(input.Id, true);
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task Disabled(EntityDto input)
        {
            await _articleManager.Enabled(input.Id, false);
        }

        [AbpAuthorize(PermissionNames.ArticleManagement)]
        public async Task<SearchResultDto<ArticleDto>> Search(SearchArticleDto input)
        {
            var query = HandleQuery(input);

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            return new SearchResultDto<ArticleDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new ArticleDto(r)).ToList()
            };
        }

        public async Task<SearchResultDto<ArticleDto>> SearchEnabled(SearchArticleDto input)
        {
            var query = HandleQuery(input);
            query = query.Where(r => r.Enabled);

            int totalCount = query.Count();
            var items = query.OrderByDescending(r => r.CreationTime).Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            return new SearchResultDto<ArticleDto>
            {
                TotalCount = totalCount,
                Items = items.Select(r => new ArticleDto{
                    Id = r.Id,
                    Title = r.Title,
                    Author = r.Author,
                    Picture = r.Picture,
                    CreationTime = r.CreationTime,
                    ClickCount = r.ClickCount,
                    Description = r.Description }).ToList()
            };
        }

        private IQueryable<Article> HandleQuery(SearchArticleDto input)
        {
            var query = _articleRepository.GetAll();
            
            if (input.Tags.Count > 0)
            {
                foreach (var tag in input.Tags)
                {
                    if (string.IsNullOrWhiteSpace(tag)) continue;
                    query = query.Where(r => r.Tags.Items.Contains(tag));
                }
            }

            if(input.SystemType != null && (int)input.SystemType != -1)
            {
                query = query.Where(r => r.SystemType == input.SystemType);
            }
            
            if (!string.IsNullOrWhiteSpace(input.Search))
            {
                switch (input.SearchTarget)
                {
                    case "title": query = query.Where(r => r.Title.Contains(input.Search)); break;
                    case "tag": query = query.Where(r => r.Tags.Items.Contains(input.Search)); break;
                    case "author": query = query.Where(r => r.Author.Contains(input.Search)); break;
                    case "source": query = query.Where(r => r.Source.Contains(input.Search)); break;
                }
            }

            if(input.Status != null && (int)input.Status != -1)
            {
                query = query.Where(r => r.Status == input.Status);
            }

            return query;
        }
    }
}
